/*User program on Nachos
  For project 2 part 3
*/

/*Author: Yuzhe Wu 2/24*/

#include "syscall.h"
#include "doctorOffice.h"
#include "user.h"

int examRoomNum = 3;
int docNum = 3;
int nurseNum = 5;
int xrayRoomNum = 2;
int patientNum = 100;
int parentNum = 1;

int bill=0;




/*Lock defination*/
/*1. The Lock with the Location*/
myLock waitingRoomLock = -1;
myLock examRoomLock[MAXEXAMROOMNUM];
myLock xrayRoomLock[MAXXRAYNUM];
myLock sittingRoomLock = -1;
myLock cashierRoomLock = -1;
myLock cabinetLock = -1;

myLock testLock = -1;

/*2. The Lock with service providers*/
myLock wrnLock = -1;
myLock nurseLock[MAXNURSENUM];
myLock docLock[MAXDOCNUM];
myLock cashierLock = -1;

/*3. The Lock for check state*/
myLock examStateLock = -1;
myLock docStateLock = -1;
myLock xrayStateLock = -1;

/*Condition variable defination*/
/*1. Person waiting for Room CV*/
myCV patientWaitingWRCV = -1;
myCV nurseWaitingWRCV = -1;
myCV patientWaitingCRCV = -1;
myCV nurseWaitingcabinetCV = -1;

/*2. Person waiting service providers at some Location*/
myCV patientWaitingNurseSRCV = -1;
myCV nurseWaitingDocCV = -1;
myCV patientWaitingNurseERCV[MAXEXAMROOMNUM];
myCV patientWaitingDocCV[MAXEXAMROOMNUM];
myCV patientWaitingNurseXRCV[MAXXRAYNUM];

/*3. Person interaction CV */
myCV wrnPatient_NurseCV = -1;
myCV nursePatientCV[MAXNURSENUM];
myCV docPatientCV[MAXDOCNUM];
myCV nurseXrayCV[MAXXRAYNUM];
myCV xrayPatientCV[MAXXRAYNUM];
myCV nurseDocCV[MAXDOCNUM];
myCV cashierPatientCV = -1;

/*Moniter variable*/
/*1. State*/
bool wrnState = BUSY;
bool cashierState=BUSY;
bool cabinetState = FREE;				
bool examState[MAXEXAMROOMNUM];
bool docState[MAXDOCNUM];
bool xrayState[MAXXRAYNUM];

/*2. Counter*/
int waitingRoomPatientCounter=0;
int waitingRoomNurseCounter=0;
int sittingRoomCounter=0;
int docRoomCounter=0;
int cashierRoomCounter=0;
int cabinetCounter=0;

int wrnTask = WRONGTASK;

/*The doctor id which response the nurse*/
int doc_NurseID = INT_MAX;
int nurseIDTOPatientSR = INT_MAX;
int patientIDTONurse = INT_MAX;
int parentIDTONurse = INT_MAX;
int nurseIDTOWRN = INT_MAX;
int docIDTOPatient[MAXEXAMROOMNUM];
int examIDTODoctor[MAXDOCNUM];
int examIDTOPatient[MAXNURSENUM];
int nurseIDTOXray[MAXXRAYNUM];
int docIDTONurse[MAXNURSENUM];
int nurseIDTOPatientER[MAXEXAMROOMNUM];
int xrayIDTOPatient[MAXNURSENUM];
int nurseIDTOPatientXR[MAXXRAYNUM];
int nurseIDVerify[MAXDOCNUM];

/*test by tang*/
int verifyPatientID[MAXEXAMROOMNUM];
int nurseSheetIDTOPatient[MAXNURSENUM];

/* NurseID List*/
int nurseIDList[MAXPATIENTNUM];
int nurseIDListNum = MAXPATIENTNUM;
int nurseIDFirstItem = 0;
int nurseIDLastItem = -1;

/*examSheet exchange*/
struct examSheet* wrnExamSheet = NULL;
struct examSheet* cashierExamSheet = NULL;
struct examSheet* wrnExamSheetEmpty = NULL;
struct examSheet* wallPocketER[MAXEXAMROOMNUM];
struct examSheet* xrayExamSheet[MAXXRAYNUM];
struct examSheet* wallPocketXR[MAXXRAYNUM];
struct examSheet* docExamSheet[MAXDOCNUM];



/*Deal with the index*/
int patientIndex = 0;
int nurseIndex = 0;
int doctorIndex = 0;
int xrayIndex = 0;

int patientLeftNum = 0; 

/*Relative index lock*/
myLock patientIndexLock = -1;
myLock nurseIndexLock = -1;
myLock doctorIndexLock = -1;
myLock xrayIndexLock = -1;
myLock patientLeftNumLock = -1;

bool debugFlag = false;

void nurseTaskDelay(){
	int r;
	int i;
	r = Rand(100)+50;
	for(i=0;i<r;i++){
		Yield();	
	}
}

int moneycalculate(struct examSheet* Sheet) {/* Calculate the total amount of the bill, Formular: money = basic($10) + shotmoney($50) + imageNum * moneyPerImage($30)*/
	int money = BASIC;   
	if(Sheet->needShot==true){
		money+=SHOTMONEY;
	}
	if(Sheet->needXray==true){
		money+=(Sheet->imageNum)*IMAGEMONEY;
	}
	return money;
}

void waitingRoomNurse(){
	int i = 0;

	struct examSheet examSheetPipe[MAXPATIENTNUM];
	struct examSheet* wrnExamSheetList[MAXPATIENTNUM];
	int wrnExamSheetListNum = MAXPATIENTNUM;
	int wrnExamSheetFirstItem = 0;
	int wrnExamSheetLastItem = -1;
	
	int patientNum = 0;
	
	/*Initial List*/
	for (i=0;i<wrnExamSheetListNum;i++) {
		wrnExamSheetList[i] = NULL;
	}
 	
	if(debugFlag == true) {
		Printf("myDEBUG: Enter waitingRoomNurse threads.\n");
	}
	
	while(1) {
		AcquireLock(waitingRoomLock);
		if(waitingRoomNurseCounter>0) { /*A nurse is in line*/
			SignalCV(waitingRoomLock, nurseWaitingWRCV);
			waitingRoomNurseCounter--;
			wrnState = BUSY;
		}
		
		else if(waitingRoomPatientCounter>0) { /*A patient is in line*/
			SignalCV(waitingRoomLock, patientWaitingWRCV);
			waitingRoomPatientCounter--;
			wrnState = BUSY;		
		}
		
		else {
			wrnState=FREE;	
		}
		
		AcquireLock(wrnLock);
		ReleaseLock(waitingRoomLock);
		
		if(debugFlag == true) {
			Printf("myDEBUG: wrn Start to wait!\n");
		} 
		
		WaitCV(wrnLock,wrnPatient_NurseCV);
		
		if(debugFlag == true) {
			Printf("myDEBUG: WRN is signal by patient or nurse!\n");
		} 
		
/*Interaction with Patient or Nurse*/
		/*Check the three possible tasks: GETFORM GIVEFORM CALLPATIENT*/
		if(wrnTask == GETFORM ) {
			
			Printf("Waiting Room nurse gives a form to Adult patient [%d]\n",patientIDTONurse);
			
			wrnExamSheetEmpty = &(examSheetPipe[patientNum]);
			patientNum ++ ;
			SignalCV(wrnLock, wrnPatient_NurseCV);
	
			if(debugFlag == true) {
				Printf("myDEBUG: WRN is ready to wait!\n");
			}
			
			WaitCV(wrnLock,wrnPatient_NurseCV);
			
			if(debugFlag == true) {
				Printf("myDEBUG:WRN has given the examSheet to a patient.\n");
			}		
		}
		else if(wrnTask == GIVEFORM) {			
			/*Append*/
			wrnExamSheetLastItem++;
			if(wrnExamSheetLastItem==wrnExamSheetListNum){
				wrnExamSheetLastItem = 0;
			}
			wrnExamSheetList[wrnExamSheetLastItem] = wrnExamSheet;
			
			
			
			if(debugFlag == true) {
				Printf("myDEBUG:WaitingRoomNurse append           %d              patient in list\n\n\n\n", wrnExamSheet->patientID);
			}
			SignalCV(wrnLock, wrnPatient_NurseCV);
			WaitCV(wrnLock, wrnPatient_NurseCV);
			
			if(debugFlag == true) {
				Printf("myDEBUG:WRN has put the a examSheet to a list.\n");
			}
			Printf("Waiting Room nurse accepts the form from Adult Patient/Parent with name [%s] and age [%d]\n", wrnExamSheet->name, wrnExamSheet->age);
			Printf("Waiting Room nurse creates an examination sheet for [Adult/Child] patient with name [%s] and age [%d]\n", wrnExamSheet->name, wrnExamSheet->age);
			Printf("Waiting Room nurse tells the Adult Patient/Parent [%s] to wait in the waiting room for a nurse\n", wrnExamSheet->name);	
		}
		
		else if (wrnTask == CALLPATIENT) {
			SignalCV(wrnLock, wrnPatient_NurseCV);
			WaitCV(wrnLock,wrnPatient_NurseCV);
			
			/*Remove*/
			wrnExamSheet = wrnExamSheetList[wrnExamSheetFirstItem];
			wrnExamSheetFirstItem++;
			if(wrnExamSheetFirstItem == wrnExamSheetListNum) {
				wrnExamSheetFirstItem =0;
			}
					
			if(debugFlag == true) {
				Printf("myDEBUG:WaitingRoomNurse remove           %d              patient in list\n\n\n", wrnExamSheet->patientID);
			}
			
			if(wrnExamSheet == NULL){
				Printf("FATAL ERROR: no more ExamSheet for nurse.\n");
			}	

			Printf("Waiting Room nurse gives examination sheet to patient[%s] to Nurse [%d].\n",wrnExamSheet->name,nurseIDTOWRN);
			SignalCV(wrnLock, wrnPatient_NurseCV);
			WaitCV(wrnLock,wrnPatient_NurseCV);		
		}
		
		else{
			Printf("ERROR:WRONG WrnTask.\n");
		}
		ReleaseLock(wrnLock);
		
		AcquireLock(patientLeftNumLock);
		if(patientLeftNum == patientNum) {
			Exit(0);
		}
		ReleaseLock(patientLeftNumLock);
	}
}

void patient() {
	struct examSheet* myExamSheet = NULL;
	int myNurseID = -1;
	int myExamID = -1;
	int myXrayID = -1;
	int myDocID = -1;
	int symptonID = -1;
	int tmpi = -1;  /*temporary image taken number*/
	int money = -1;
	
	/*Get the index*/
	int index = -1;
	AcquireLock(patientIndexLock);
	index = patientIndex;
	patientIndex++;
	ReleaseLock(patientIndexLock);
	
	Printf("Adult Patient [%d] has entered the Doctor's Office Waiting Room.\n",index);
	AcquireLock(waitingRoomLock);
	
	if(debugFlag == true) {
		Printf("myDEBUG: patient Acquire waitingRoomLock start!\n");
	}
	
	if (wrnState == BUSY) {
		waitingRoomPatientCounter++;
		Printf("Adult Patient [%d] gets in line of the Waiting Room Nurse to get registeration form.\n",index);
		WaitCV(waitingRoomLock,patientWaitingWRCV);	
	}
	else {	
		wrnState = BUSY;
	}
	ReleaseLock(waitingRoomLock);
	
/*Interaction patient&wrn,Get form*/
	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%d] prepare to get form.\n",index);
	}
	
	AcquireLock(wrnLock);

	wrnTask = GETFORM;
	patientIDTONurse = index;
	
	if(debugFlag == true) {
		Printf("myDEBUG: Patient ready to signal wrn!\n");
	}
	SignalCV(wrnLock, wrnPatient_NurseCV);
	WaitCV(wrnLock,wrnPatient_NurseCV);
	Printf("[Adult patient/Parent of child patient][%d] gets the form from the Waiting Room Nurse.\n",index);
	myExamSheet = wrnExamSheetEmpty;
	
	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%d] get registeration form.\n",index);
	}
	SignalCV(wrnLock, wrnPatient_NurseCV);
	wrnTask = WRONGTASK;
	ReleaseLock(wrnLock);
	
	/*The patient fill out the examSheet*/
	myExamSheet->patientID = index;
	myExamSheet->name = "Patient";
	
	myExamSheet->age = Rand(100);  /*Self define syscall; Random Generate the patient age, Uniform distributed in [0 100]*/
	
	symptonID = Rand(3);
	if(symptonID==0) {
		myExamSheet->symptom = "Pain";
	}
	else if(symptonID==1) {
		myExamSheet->symptom = "Nausea";
	}
	else if(symptonID==2) {
		myExamSheet->symptom = "Hear Alien Voices";
	}
	else {
		Printf("ERROR: Wrong symptom\n");
	}
	
	/*Finish filling out the form,Queuing to give the form*/
	
	if(debugFlag == true) {
		Printf("myDEBUG: patient ready to give the form\n");
	}
	AcquireLock(waitingRoomLock);
	if ( wrnState == BUSY) {
		waitingRoomPatientCounter++;
		Printf("Adult Patient [%d] gets in line of the Waiting Room Nurse to submit registeration form.\n",index);
		WaitCV(waitingRoomLock,patientWaitingWRCV);
	}
	else {
		wrnState = BUSY;
	}
	AcquireLock(wrnLock);
	ReleaseLock(waitingRoomLock);
	
	/*Interaction patient&wrn,Give form*/
	wrnTask = GIVEFORM;
	wrnExamSheet = myExamSheet;	
	SignalCV(wrnLock, wrnPatient_NurseCV);
	WaitCV(wrnLock,wrnPatient_NurseCV);
	Printf("[Adult patient/Parent of child patient][%d] submits the filled form to the Waiting Room Nurse.\n",index);
	AcquireLock(sittingRoomLock);
	wrnTask = WRONGTASK;
	if (debugFlag == true) {
		if(wrnExamSheet == NULL){
			Printf("DEBUG: wrnExamSheet NULL!!!!!!!\n");
		}
		else{
			Printf("DEBUG: wrnExamSheet not NULL\n");
		}
		Printf("myDEBUG: Adult Patient [%d] submit the examSheet e.\n",index);
	}
	SignalCV(wrnLock, wrnPatient_NurseCV);

	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%d] gets finish the examSheet.\n",index);
	}
	
	/*Patient interact with nurse*/
	ReleaseLock(wrnLock);
	
	if(debugFlag == true) {
		Printf("myDEBUG:Patient[%d]waiting for nurse to come\n", index);
	}
	
	sittingRoomCounter++;
	AcquireLock(testLock);
	ReleaseLock(sittingRoomLock);
	WaitCV(testLock,patientWaitingNurseSRCV);
	ReleaseLock(testLock);
	
	myNurseID = nurseIDTOPatientSR;
	if(debugFlag == true) {
		Printf("myDEBUG:\n\nPatient [%d] is waken up by Nurse [%d] in waiting Room\n\n", index, myNurseID);
	}
	
/*Line 647 - line 662 for debug in original doctorOffice.cc*/
	AcquireLock(nurseLock[myNurseID]);
	SignalCV(nurseLock[myNurseID], nursePatientCV[myNurseID]);
	myExamID = examIDTOPatient[myNurseID];
	
	/*Find the nurse to interaction with!*/
	WaitCV(nurseLock[myNurseID],nursePatientCV[myNurseID]);
   /*Wait for the nurse to wake him up with the proper examRoom index*/
	Printf("[Adult Patient/Parent] [%s%d] is following Nurse [%d] to Examination Room [%d]\n", myExamSheet->name,myExamSheet->patientID,myNurseID,myExamID);
	Printf("[Adult Patient/Parent] [%s%d] has arrived at Examination Room [%d]\n", myExamSheet->name,myExamSheet->patientID,myExamID);
	
	AcquireLock(examRoomLock[myExamID]);
	SignalCV(nurseLock[myNurseID], nursePatientCV[myNurseID]);
	
	ReleaseLock(nurseLock[myNurseID]);

	if(debugFlag == true) {
		Printf("myDEBUG: patient [%s%d] finish interaction with nurse\n", myExamSheet->name,myExamSheet->patientID);
	}

	WaitCV(examRoomLock[myExamID],patientWaitingDocCV[myExamID]);
	/*By now, I am waiting in exam room for doctor*/
	
	/*Start interaction doctor & patient*/
	myDocID = docIDTOPatient[myExamID];

	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%s%d] has interact with Doctor [%d]\n",myExamSheet->name,myExamSheet->patientID,myDocID);
	}
	
	AcquireLock(docLock[myDocID]);
	ReleaseLock(examRoomLock[myExamID]);
	
	SignalCV(docLock[myDocID],docPatientCV[myDocID]);
	WaitCV(docLock[myDocID],docPatientCV[myDocID]);
	myExamSheet = docExamSheet[myDocID];  /*Get back the ExamSheet From Doc*/

	if(index != docExamSheet[myDocID]->patientID){
		Printf("myDEBUG:FATAL ERROR: patient [%d] doctor give me the wrong examsheet with patient id %d\n\n\n\n\n", index, docExamSheet[myDocID]->patientID);
	}
	
	if(debugFlag == true) {
		Printf("myDEBUG: Patient [%s%d] receive the result from doc\n", myExamSheet->name,myExamSheet->patientID);
		Printf("my Patient [%s%d] receive the result from doc\n", myExamSheet->name, myExamSheet->patientID);
	}
	
	if(myExamSheet->needXray == true) {
		Printf("Adult Patient [%s%d] has been informed by Doctor [%d] that he needs an Xray\n", myExamSheet->name,myExamSheet->patientID,myDocID);
	}
	
	if(myExamSheet->needShot == true) {
		Printf("Adult Patient [%s%d] has been informed by Doctor [%d] that he will be administered a shot\n", myExamSheet->name,myExamSheet->patientID,myDocID);
	}
	
	Printf("Adult Patient [%s%d] has been diagnosed by Doctor [%d]\n", myExamSheet->name,myExamSheet->patientID,myDocID);

	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%s%d] has finish with Doctor [%d]\n", myExamSheet->name,myExamSheet->patientID,myDocID);
	}
	
	AcquireLock(examRoomLock[myExamID]);
	SignalCV(docLock[myDocID],docPatientCV[myDocID]);
	ReleaseLock(docLock[myDocID]);

	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%s%d] waiting in the ER [%d]\n", myExamSheet->name,myExamSheet->patientID,myExamID);
	}
	
	if(myExamSheet->nextDestination == XRAYROOM) {
		Printf("Adult Patient [%d] waits for a Nurse to escort them to the Xray room.\n", myExamSheet->patientID);
		/*Other print for Parent*/
	}
	
	WaitCV(examRoomLock[myExamID],patientWaitingNurseERCV[myExamID]);	
	ReleaseLock(examRoomLock[myExamID]);
	
	/*at exam room, goto exam room to take shot*/
	if(myExamSheet->needShot == true) {
		myNurseID = nurseIDTOPatientER[myExamID];
		Printf("Adult Patient/Parent [%s%d] says, yes I am/He is ready for the shot?.\n", myExamSheet->name, myExamSheet->patientID);
		AcquireLock(nurseLock[myNurseID]);
		SignalCV(nurseLock[myNurseID],nursePatientCV[myNurseID]);    /*Start interacting with patient*/
		AcquireLock(examRoomLock[myExamID]);
		ReleaseLock(nurseLock[myNurseID]);
	
		if(myExamSheet->needXray == true) {
			Printf("Adult Patient [%d] waits for a Nurse to escort them to the Xray room.\n", myExamSheet->patientID);
			/*Print for parent*/
		}
		
		WaitCV(examRoomLock[myExamID],patientWaitingNurseERCV[myExamID]);
		ReleaseLock(examRoomLock[myExamID]);		
	}
	
	/*patient at exam room, goto xray wait at Xray room for nurse to take me to exam room 
	  then interact with doctor at exam room,end up waiting nurse in exam room
	*/
	
	if(myExamSheet->needXray == true) {
		/*get information from nurse, and then leave exam room*/
		myXrayID = xrayIDTOPatient[myExamID];
		if(debugFlag == true) {
			Printf("myDEBUG:Patient my xrayID is %d\n", myXrayID);
		}
		
		AcquireLock(examRoomLock[myExamID]);
		examState[myExamID] = FREE;
		
		if(debugFlag == true) {
			Printf("myDEBUG:Patient set the exam Room FREE\n");
		}
		
		ReleaseLock(examRoomLock[myExamID]);
		AcquireLock(xrayRoomLock[myXrayID]);

		if(debugFlag == true) {
			Printf("myDEBUG:PATIENT GONNA TO SIGNAL EXRAY MAN!!\n");
		}
		
		SignalCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);

		/*waiting for the instruction of XRay techinician*/
		WaitCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
	
		Printf("[Adult Patient/Parent] [%s%d] gets on the table.\n",myExamSheet->name,myExamSheet->patientID);
		Printf("[Adult Patient/Parent] [%s%d] has been asked to take an Xray.\n",myExamSheet->name,myExamSheet->patientID);
		SignalCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);

		if((myExamSheet->imageNum)>1) {
			for(tmpi=0;tmpi<(myExamSheet->imageNum-1);tmpi++) {
				WaitCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
				Printf("[Adult Patient/Parent] [%s%d] moves for the next Xray\n",myExamSheet->name,myExamSheet->patientID);
				SignalCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
			}		
		}
		WaitCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
		if(debugFlag == true) {
			Printf("DEBUG:[Adult Patient/Parent] [%s%d]waits for a Nurse to escort him/her to Exam room.\n",myExamSheet->name,myExamSheet->patientID);
		}
		/*first patient should wait fot waking up by nurse, and then he wakes the Xray Technician up*/
		WaitCV(xrayRoomLock[myXrayID],patientWaitingNurseXRCV[myXrayID]); /*wait for nurse take me to exam room*/
		SignalCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
		ReleaseLock(xrayRoomLock[myXrayID]);
		
		myNurseID = nurseIDTOPatientXR[myXrayID];
		myExamID = examIDTOPatient[myNurseID];	

		AcquireLock(nurseLock[myNurseID]);
		AcquireLock(examRoomLock[myExamID]);
		SignalCV(nurseLock[myNurseID],nursePatientCV[myNurseID]);
		ReleaseLock(nurseLock[myNurseID]);
		WaitCV(examRoomLock[myExamID],patientWaitingDocCV[myExamID]);
		
		/*patient interact with doctor*/
		myDocID = docIDTOPatient[myExamID];
		AcquireLock(docLock[myDocID]);
		SignalCV(docLock[myDocID],docPatientCV[myDocID]);
		ReleaseLock(docLock[myDocID]);
		WaitCV(examRoomLock[myExamID],patientWaitingNurseERCV[myExamID]);
		ReleaseLock(examRoomLock[myExamID]);
	}  /*End of need Xray*/  

	AcquireLock(examRoomLock[myExamID]);
	examState[myExamID] = FREE;
	ReleaseLock(examRoomLock[myExamID]);

	
	AcquireLock(cashierRoomLock);
	Printf("[Adult Patient/Parent][%s%d]enters the queue of cashier\n",myExamSheet->name,myExamSheet->patientID);

	/*Start to interact with cashier*/
	if(cashierState == FREE){
		cashierState=BUSY;
		ReleaseLock(cashierRoomLock);
	}
	
	else{
		cashierRoomCounter++;
		WaitCV(cashierRoomLock,patientWaitingCRCV);
		ReleaseLock(cashierRoomLock);
	}	
	
	/*Enter the cahiser room and start interacting*/
	Printf("Adult Patient[%d] has reached cashier.\n", myExamSheet->patientID);
	/*Print for parent*/
	
	AcquireLock(cashierLock);
	if(debugFlag == true) {
		Printf("myDEBUG:Patient [%d] :my name is %s\n", myExamSheet->patientID, myExamSheet->name);
	}
	cashierExamSheet = myExamSheet;
	
	Printf("Adult Patient [%d] hands over his examsheet to the cashier\n",myExamSheet->patientID);
	/*Print for parent*/
	
	SignalCV(cashierLock,cashierPatientCV);
	WaitCV(cashierLock,cashierPatientCV);
	
	money=bill;
	Printf("Adult Patient [%d] pays the cashier $ %d\n",myExamSheet->patientID, money);
	/*print for parent*/
	SignalCV(cashierLock,cashierPatientCV);
	WaitCV(cashierLock,cashierPatientCV);
	
	Printf("Adult Patient [%d] receives a receipt from the cashier\n",myExamSheet->patientID);
	SignalCV(cashierLock,cashierPatientCV);
	
	AcquireLock(patientLeftNumLock);
	patientLeftNum++;
	if(debugFlag == true) {
		Printf("myDEBUG: The number of patient that leave is %d \n", patientLeftNum);
	}
	ReleaseLock(patientLeftNumLock);
	
	ReleaseLock(cashierLock);

	Printf("Adult Patient [%d] leaves the doctor office.\n",myExamSheet->patientID);
	/*print for parent*/
	Exit(0);
	
}

void Nurse( ) {
	int myERID = -1;	/*the empty exam room I find to bring patient to when patient in waiting room, or xray*/
	int myDocID = -1;/*the free doctor I find when patient in exam room*/
	int myXRID = -1; 
	int myWallPocketERID = -1;	/*the exam room No. which has a filled wall pocket*/
	int myWallPocketXRID = -1;	/*the eray room No. which has a filled wall pocket*/
	int *tmpNurseID = NULL;
	
	struct examSheet* myExamSheet;
	
	/*Get index*/
	int id = -1;
	AcquireLock(nurseIndexLock);
	id = nurseIndex;
	nurseIndex++;
	ReleaseLock(nurseIndexLock);
	
	if(debugFlag == true) {
		Printf("myDEBUG: Nurse [%d]: I entered!\n", id);
	}
	
	while(1){
		if(debugFlag == true) {
			Printf("myDEBUG:Nurse[%d]'s gonna to check waiting room\n", id);
		}
	
		/*check waiting Room if anyone waiting*/
		
		AcquireLock(sittingRoomLock);
		if(sittingRoomCounter == 0) {
			ReleaseLock(sittingRoomLock);
		}

		else { /*Some one is waiting*/
			/*Check Examination room state*/
			AcquireLock(examStateLock);
			
			for(myERID=0;myERID<examRoomNum;myERID++){
				if(examState[myERID] == FREE) {
					examState[myERID] = BUSY;
					if(debugFlag == true) {
						Printf("myDEBUG:Nurse%d find examRoom %d FREE\n",id,myERID);
					}					
					break;
				}
			}
			ReleaseLock(examStateLock);
			
			if(myERID < examRoomNum) {  /*Any empty exam room?*/
				sittingRoomCounter --;
				ReleaseLock(sittingRoomLock);
				AcquireLock(waitingRoomLock);
				if(wrnState == BUSY){
					waitingRoomNurseCounter ++;
					WaitCV(waitingRoomLock,nurseWaitingWRCV);
				}
				else {
					wrnState = BUSY;
				}
				
				AcquireLock(testLock);
				
				
				ReleaseLock(waitingRoomLock);
				AcquireLock(wrnLock);
				wrnTask = CALLPATIENT;
				
				SignalCV(wrnLock, wrnPatient_NurseCV);	/*wake up wrn, start interacting*/
				WaitCV(wrnLock,wrnPatient_NurseCV);
				Printf("Nurse [%d] tells Waiting Room Nurse to give a new examination sheet.\n",id);
				nurseIDTOWRN= id;
				SignalCV(wrnLock, wrnPatient_NurseCV);
				WaitCV(wrnLock,wrnPatient_NurseCV);
				
				wrnTask = WRONGTASK;
				myExamSheet = wrnExamSheet;
				if(debugFlag == true) {
					Printf("myDEBUG:Nurse[%d]get a patient with name %s%d\n", id, myExamSheet->name,myExamSheet->patientID);
				}
				
				SignalCV(wrnLock, wrnPatient_NurseCV);
				
				/*prepare the data to interact with patient: nurseIDTOPatientSR*/
				nurseIDTOPatientSR = id;
				nurseSheetIDTOPatient[id] = myExamSheet->patientID;
				
				/*wake patient up and let him wait for the nurse*/
				AcquireLock(nurseLock[id]);
				SignalCV(testLock,patientWaitingNurseSRCV);
				ReleaseLock(testLock);
		
				if(debugFlag == true) {
					Printf("myDEBUG:Nurse[%d] try to wake up a patient with name %s%d\n",id, myExamSheet->name,myExamSheet->patientID);
				}
				
				/*make sure wait nurseLock before p signal,get examsheet, 
				end interacting with wrn*/
				
				Printf("Nurse [%d] escorts Adult/Child Patient [%s%d] to the examination room [%d].\n", id, myExamSheet->name,myExamSheet->patientID,myERID);
				examIDTOPatient[id]=myERID;
				
				WaitCV(nurseLock[id],nursePatientCV[id]);
				ReleaseLock(wrnLock);
				SignalCV(nurseLock[id],nursePatientCV[id]);
				
				/*interact with patient to do first exam*/
				Printf("Nurse [%d] takes the temperature and blood pressure of Adult Patient/Parent [%s%d].\n", id, myExamSheet->name,myExamSheet->patientID);
				Printf("Nurse [%d] asks Adult Patient/Parent [%s%d] what Symptoms do you have?\n", id, myExamSheet->name,myExamSheet->patientID);
				Printf("Nurse [%d] writes all the information of Adult Patient/Parent [%s%d] in his examination sheet.\n", id, myExamSheet->name,myExamSheet->patientID);
				
				/*note right now patient need to get the ExamRoomLock*/
				WaitCV(nurseLock[id],nursePatientCV[id]);
				if(debugFlag == true) {
					Printf("myDEBUG: Nurse [%d] finish Adult Patient/Parent [%s%d]\n",id, myExamSheet->name,myExamSheet->patientID);
				}
				ReleaseLock(nurseLock[id]);
				
				/*Now go and bring a doctor*/
				AcquireLock(docStateLock);
				for(myDocID=0;myDocID<docNum;myDocID++){
					if(docState[myDocID] == FREE) {
						docState[myDocID] = BUSY;
						break;
					}
				}
				ReleaseLock(docStateLock);
				
				if(myDocID >= docNum) {
					AcquireLock(docStateLock);
					docRoomCounter++;
					
					/*Append*/
					nurseIDLastItem++;
					if(nurseIDLastItem==nurseIDListNum) {
						nurseIDLastItem = 0;
					}
					nurseIDList[nurseIDLastItem] = id;
					
					
					WaitCV(docStateLock,nurseWaitingDocCV);
					myDocID = docIDTONurse[id];
					
					if(id!=nurseIDVerify[myDocID]){
						Printf("DEBUG FATAL ERROR: ERROR when pop and push nurse id in list\n");
					}
					
					SignalCV(docStateLock,nurseWaitingDocCV);
					ReleaseLock(docStateLock);
							
				}
				
				/*by now, we get a doctor with # myDocID*/
				/*we need to tell the doctor the exam room number and the patient id*/
				AcquireLock(docLock[myDocID]);
				docExamSheet[myDocID] = myExamSheet;
				examIDTODoctor[myDocID]= myERID;
				Printf("Nurse [%d] informs Doctor [%d] that Adult/Child Patient [%s%d] is waiting in the examination room %d.\n", id, myDocID, myExamSheet->name,myExamSheet->patientID,myERID);
				Printf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Adult/Child Patient [%s%d].\n", id, myDocID, myExamSheet->name,myExamSheet->patientID);
				SignalCV(docLock[myDocID],nurseDocCV[myDocID]);
				WaitCV(docLock[myDocID],nurseDocCV[myDocID]);
				ReleaseLock(docLock[myDocID]);
				
				Printf("DEBUG: Nurse [%d] finish with Doctor [%d] \n", id, myDocID);			
			}
			
			else {
				ReleaseLock(sittingRoomLock);
			}		
		}	/*End of else someone waiting*/
		
		nurseTaskDelay();
		
		/*check Examination Room wall pocket*/
		for( myWallPocketERID=0;myWallPocketERID<examRoomNum;myWallPocketERID++) {
			AcquireLock(examRoomLock[myWallPocketERID]);
			if(wallPocketER[myWallPocketERID]!= NULL){
				myExamSheet = wallPocketER[myWallPocketERID];
				if(debugFlag == true) {
					Printf("myDEBUG:Nurse[%d] find wall pocket exam [%d] filled.\n", id, myWallPocketERID);
				}
				wallPocketER[myWallPocketERID] = NULL;
				ReleaseLock(examRoomLock[myWallPocketERID]);
				break;
			}
			ReleaseLock(examRoomLock[myWallPocketERID]);
		}
		
		if(myWallPocketERID<examRoomNum) { /*if any wall pocket, get inside and take patient to shot or Xray*/
			if(debugFlag == true) {
				Printf("myDEBUG:Nurse->nextDestination %d\n",myExamSheet->nextDestination);
			}
			if(myExamSheet->nextDestination == EXAMROOM){	/*take patient to shot*/
				AcquireLock(cabinetLock);
				if(cabinetState == BUSY){
					cabinetCounter++;
					WaitCV(cabinetLock,nurseWaitingcabinetCV);
					if(debugFlag == true) {
						Printf("myDEBUG: nurse [%d] waiting for cabinet Lock.\n", id);
					}
				}
				else{
					cabinetState = BUSY;
				}
				ReleaseLock(cabinetLock);
				/*by here, we need to get into the cabinet*/
				Printf("Nurse [%d] goes to supply cabinet to give to take medicine for Adult/Child Patient [%s%d].\n", id, myExamSheet->name,myExamSheet->patientID);
				AcquireLock(cabinetLock);
				if(cabinetCounter > 0){
					cabinetCounter --;
					SignalCV(cabinetLock, nurseWaitingcabinetCV);
					if(debugFlag == true) {
						Printf("myDEBUG: Nurse [%d] Signal the cabinetCV", id);
					}
				}
				else{
					cabinetState = FREE;
				}
				ReleaseLock(cabinetLock);
				
				/*by here, we got the medicine, and we need to give shot to patient*/
				AcquireLock(examRoomLock[myWallPocketERID]);
				nurseIDTOPatientER[myWallPocketERID] = id; /*prepare the data to interaction with patient which examroom to go*/
				
				AcquireLock(nurseLock[id]);
				Printf("Nurse [%d] asks Adult/Child Patient [%s%d] \"Are you ready for the shot?\"\n", id, myExamSheet->name,myExamSheet->patientID);
				SignalCV(examRoomLock[myWallPocketERID], patientWaitingNurseERCV[myWallPocketERID]);
			
				ReleaseLock(examRoomLock[myWallPocketERID]);
				WaitCV(nurseLock[id],nursePatientCV[id]);
				Printf("Nurse [%d] tells Adult/Child Patient [%s%d] \"Your shot is over.\"\n", id, myExamSheet->name,myExamSheet->patientID);

				if(myExamSheet->needXray == true){
					if(debugFlag == true) {
						Printf("myDEBUG:Nurse[%d] find patient need Xray\n", id);
					}
					myExamSheet->nextDestination = XRAYROOM;	
				}
				else {
					myExamSheet->nextDestination = CASHIER;
				}
				ReleaseLock(nurseLock[id]);
				if(debugFlag == true) {
					Printf("myDEBUG:nextDestination:%d",myExamSheet->nextDestination);
					Printf("myDEBUG:Nurse[%d] have given shot to patient[%d], and released my own nurse lock\n",id, myExamSheet->patientID);
				}
			} /*end of if patient take shot*/
			
			if(myExamSheet->nextDestination == XRAYROOM){ /*need go to Xray*/
				if(debugFlag == true) {
					Printf("myDEBUG:Nurse[%d] is checking xray state\n", id);
				}
				AcquireLock(xrayStateLock);
				for(myXRID=0;myXRID<xrayRoomNum;myXRID++){
					if(debugFlag == true) {
						Printf("myDEBUG:Nurse[%d] is checking xray state %d\n", id, myXRID);
					}
					if(xrayState[myXRID] == FREE){
						xrayState[myXRID] = BUSY;
						if(debugFlag == true) {
							Printf("myDEBUG:Nurse[%d] find empty xray room\n", id);
						}
						AcquireLock(xrayRoomLock[myXRID]);
						xrayExamSheet[myXRID] = myExamSheet;
						ReleaseLock(xrayRoomLock[myXRID]);
						break;
					}
				}
				ReleaseLock(xrayStateLock);
				
				if(myXRID<xrayRoomNum){ /*have empty xray room, go to xray*/
					AcquireLock(examRoomLock[myWallPocketERID]);
					xrayIDTOPatient[myWallPocketERID] = myXRID;
					
					Printf("Nurse [%d] escorts %s%d to the X-ray room [%d].\n", id, myExamSheet->name,myExamSheet->patientID,myXRID);
					SignalCV(examRoomLock[myWallPocketERID], patientWaitingNurseERCV[myWallPocketERID]);
					ReleaseLock(examRoomLock[myWallPocketERID]);
				}
				else{	/*no empty room*/
					AcquireLock(examRoomLock[myWallPocketERID]);
					wallPocketER[myWallPocketERID] = myExamSheet;
					ReleaseLock(examRoomLock[myWallPocketERID]);	
				}
			} /*end of if go to next goto xray*/
			
			if(myExamSheet->nextDestination == CASHIER){
				AcquireLock(examRoomLock[myWallPocketERID]);
				Printf("Nurse [%d] escorts %s%d to Cashier.\n",id, myExamSheet->name,myExamSheet->patientID);
				verifyPatientID[myWallPocketERID] = myExamSheet->patientID;
				SignalCV(examRoomLock[myWallPocketERID], patientWaitingNurseERCV[myWallPocketERID]);
				ReleaseLock(examRoomLock[myWallPocketERID]);
			}  /*end of if need to go to cashier.*/
		} /*end of if any wall pocket*/
	
		nurseTaskDelay();
	
		/*Printf("DEBUG:Nurse[%d]'s gonna to check xray room\n", id);*/
		/*check Xray Room wall pocket*/
		for(myWallPocketXRID=0;myWallPocketXRID<xrayRoomNum;myWallPocketXRID++){
			AcquireLock(xrayRoomLock[myWallPocketXRID]);
			if(wallPocketXR[myWallPocketXRID] != NULL) {
				myExamSheet = wallPocketXR[myWallPocketXRID];
				wallPocketXR[myWallPocketXRID] = NULL;
				if(debugFlag == true) {
					Printf("myDEBUG:Nurse [%d] find this myWallPocketXRID is not empty", myWallPocketXRID);
					Printf("myDEBUG:Nurse [%d] find xray wall pocket with name %s%d",id, myExamSheet->name,myExamSheet->patientID);
				}
				nurseIDTOPatientXR[myWallPocketXRID] = id;	/*prepare the data to interact with patient*/
				ReleaseLock(xrayRoomLock[myWallPocketXRID]);
				break;
			}
			ReleaseLock(xrayRoomLock[myWallPocketXRID]);	
		}
		
		if(myWallPocketXRID<xrayRoomNum) {
			/*check if any empty examination room*/
			AcquireLock(examStateLock);
			for(myERID=0;myERID<examRoomNum;myERID++){
				if(examState[myERID] == FREE){
					examState[myERID] = BUSY;
					AcquireLock(examRoomLock[myERID]);
					break;
				}						
			}
			ReleaseLock(examStateLock);
			
			if(myERID<examRoomNum){ /*if any empty examination room*/
				AcquireLock(xrayRoomLock[myWallPocketXRID]);
				AcquireLock(nurseLock[id]);
				examIDTOPatient[id] = myERID; /*prepare the data to interact with patient*/
				ReleaseLock(examRoomLock[myERID]);
				Printf("Nurse [%d] escorts %s%d to the examination room [%d].\n", id, myExamSheet->name,myExamSheet->patientID,myERID);
				
				SignalCV(xrayRoomLock[myWallPocketXRID],patientWaitingNurseXRCV[myWallPocketXRID]);
				ReleaseLock(xrayRoomLock[myWallPocketXRID]);
				WaitCV(nurseLock[id],nursePatientCV[id]);
				ReleaseLock(nurseLock[id]);
			
			
				/*nurse go to get the doctor*/
				AcquireLock(docStateLock);
				for(myDocID=0;myDocID<docNum;myDocID++){
					if(docState[myDocID] == FREE) {
						docState[myDocID] = BUSY;
						break;
					}
				}
				ReleaseLock(docStateLock);
			
				if(myDocID >= docNum){	/*no doctor free, wait*/
					AcquireLock(docStateLock);
					docRoomCounter++;
					
					/*Append*/
					nurseIDLastItem++;
					if(nurseIDLastItem==nurseIDListNum) {
						nurseIDLastItem = 0;
					}
					nurseIDList[nurseIDLastItem] = id;

					WaitCV(docStateLock,nurseWaitingDocCV);
					myDocID = docIDTONurse[id]; /*Doctor tell the nurse his ID*/
				
					if(id!=nurseIDVerify[myDocID]){
						Printf("DEBUG FATAL ERROR: ERROR when pop and push nurse id in list\n");
					}
					SignalCV(docStateLock,nurseWaitingDocCV);
					ReleaseLock(docStateLock);
				}
			
				/*by now, we get a doctor myDOCID*/
				AcquireLock(docLock[myDocID]);
				docExamSheet[myDocID] = myExamSheet;
				examIDTODoctor[myDocID]= myERID; 
				Printf("Nurse [%d] informs Doctor [%d] that Adult/Child Patient [%s%d] is waiting in the examination room %d.\n", id, myDocID, myExamSheet->name,myERID,myExamSheet->patientID);
				Printf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Adult/Child Patient [%s%d].\n", id, myDocID, myExamSheet->name,myExamSheet->patientID);
				SignalCV(docLock[myDocID],nurseDocCV[myDocID]);
				WaitCV(docLock[myDocID],nurseDocCV[myDocID]);
				ReleaseLock(docLock[myDocID]);
			}	/*end of if any empty exam room*/
	
		else{	/*if no empty exam room*/
			AcquireLock(xrayRoomLock[myWallPocketXRID]);
			wallPocketXR[myWallPocketXRID] = myExamSheet;
			ReleaseLock(xrayRoomLock[myWallPocketXRID]);
		}	/*end if no empty room*/
		
	}	
		nurseTaskDelay();
		
		AcquireLock(patientLeftNumLock);
		if(patientLeftNum == patientNum) {
			Exit(0);
		}
		ReleaseLock(patientLeftNumLock);
	
	} /*end-while*/
}

void doctor( ) {
	int mypatientERID = -1;
	int myNurseID = -1;
	int *tmpNurseID = NULL;
	/*Get index*/
	int id = -1;
	AcquireLock(doctorIndexLock);
	id = doctorIndex;
	doctorIndex++;
	ReleaseLock(doctorIndexLock);
	
	if(debugFlag == true) {
		Printf("myDEBUG: doctor [%d]: I entered!\n", id);
	}
	
	while(1){
		AcquireLock(docStateLock);
		if(docRoomCounter > 0) {	/*A nurse is in line*/
						
			/*Remove*/
			myNurseID = nurseIDList[nurseIDFirstItem];
			nurseIDFirstItem ++;
			if(nurseIDFirstItem == nurseIDListNum) {
				nurseIDFirstItem =0;
			}
			if(myNurseID == -1) {
				Printf("DEBUG FATAL ERROR: doctor [%d] don't have nurse waiting.\n",id);	
			}
						
			docIDTONurse[myNurseID] = id;
			nurseIDVerify[id] = myNurseID;
			docRoomCounter--;
			docState[id] = BUSY;
		
			SignalCV(docStateLock, nurseWaitingDocCV);
			
			if(debugFlag == true) {
				Printf("myDEBUG:doctor [%d] has waken up a nurse\n",id);
			}
			WaitCV(docStateLock,nurseWaitingDocCV);
		}
		else {	/*No nurse is waiting, but which do not means the doctor should be idle*/
			docState[id] = FREE;
		}
		
		AcquireLock(docLock[id]);
		ReleaseLock(docStateLock);
			
		if(debugFlag == true) {
			Printf("myDEBUG: doctor [%d] is waiting for nurse\n", id);
		}
		WaitCV(docLock[id],nurseDocCV[id]); /*Wait for nurse*/
		
		mypatientERID = examIDTODoctor[id];
		SignalCV(docLock[id], nurseDocCV[id]);
		ReleaseLock(docLock[id]);
		AcquireLock(examRoomLock[mypatientERID]);
		if(debugFlag == true) {
			Printf("myDEBUG: Doctor [%d] is finish interact with nurse\n",id);
		}	
		Printf("Doctor [%d] is leaving their office.\n", id);
	
		/*Start interaction doctor & patient*/
		docIDTOPatient[mypatientERID] = id;
		AcquireLock(docLock[id]);
		SignalCV(examRoomLock[mypatientERID],patientWaitingDocCV[mypatientERID]);
		ReleaseLock(examRoomLock[mypatientERID]);
	
		WaitCV(docLock[id],docPatientCV[id]);
		
		if(docExamSheet[id]->nextDestination == NOWHERE){ /*First interaction with patient*/
			Printf("Doctor [%d] is reading the examination sheet of [Adult/Child] Patient [%s%d] in Examination room [%d]\n",id,docExamSheet[id]->name,docExamSheet[id]->patientID,mypatientERID);
		
			if(Rand(4) == 0) {	/*25% need a shot*/
				docExamSheet[id]->needShot = true;
				Printf("Doctor [%d] notes down in the sheet that [Adult/Child] Patient [%s%d] needs to be given a shot in Examination room [%d]\n",id,docExamSheet[id]->name,docExamSheet[id]->patientID,mypatientERID);
			}
			else {
				docExamSheet[id]->needShot = false;
			}
			
			if(Rand(4) == 1) {
				docExamSheet[id]->needXray = true;
				Printf("Doctor [%d] notes down in the sheet that Xray is needed for [Adult/Child] Patient [%s%d] in Examination room [%d]\n",id,docExamSheet[id]->name,docExamSheet[id]->patientID,mypatientERID);
				docExamSheet[id]->imageNum = Rand(3) + 1;
			}
			else{
				docExamSheet[id]->needXray = false;
			}
			
			if((docExamSheet[id]->needShot == false) && (docExamSheet[id]->needXray == false)) {
				Printf("Doctor [%d] diagnoses [Adult/Child] Patient [%s%d] to be fine and is leaving Examination Room [%d]\n",id,docExamSheet[id]->name,docExamSheet[id]->patientID,mypatientERID);
			}
			
			if(docExamSheet[id]->needShot == true){
				docExamSheet[id]->nextDestination = EXAMROOM;
			}
			else if(docExamSheet[id]->needXray == true){
				docExamSheet[id]->nextDestination = XRAYROOM;
			}
			else{
				docExamSheet[id]->nextDestination = CASHIER;
			}

			if(debugFlag == true) {
				Printf("myDEBUG: Doctor [%d] FIRST interact [Adult/Child] Patient [%s%d] is leaving Examination Room [%d]\n",id,docExamSheet[id]->name,docExamSheet[id]->patientID,mypatientERID);
			}
			SignalCV(docLock[id],docPatientCV[id]);
			WaitCV(docLock[id],docPatientCV[id]);
			if(debugFlag == true) {
				Printf("myDEBUG DEBUG: Doctor [%d] FIRST interact [Adult/Child] Patient [%s%d] is leaving Examination Room [%d]\n",id,docExamSheet[id]->name,docExamSheet[id]->patientID,mypatientERID);
			}
		}
		
		else{  /*Second interaction with Patient*/
			if(debugFlag == true) {
				Printf("myDEBUG DEBUG: Doctor [%d] SECOND interact [Adult/Child] Patient [%s%d] is leaving Examination Room [%d]\n",id,docExamSheet[id]->name,docExamSheet[id]->patientID,mypatientERID);
			}
		
			Printf("Doctor [%d] is examining the Xrays of Adult Patient [%d] in Examination room [%d].\n", id, docExamSheet[id]->patientID, mypatientERID);
			/*print for parent*/
			Printf("Doctor [%d] has left Examination Room [%d].\n", id, mypatientERID);
			docExamSheet[id]->nextDestination = CASHIER;
		}
		
		AcquireLock(examRoomLock[mypatientERID]);
		wallPocketER[mypatientERID] = docExamSheet[id]; /*Post the examSheet in the Wall pocket*/
		if(debugFlag == true) {
			Printf("myDEBUG: doctor[%d] put the exam sheet with name %s%d in wall pocket exam room\n", id, wallPocketER[mypatientERID]->name,wallPocketER[mypatientERID]->patientID);
		}
		
		if(wallPocketER[mypatientERID]->needXray == false){
			if(debugFlag == true) {
				Printf("myDEBUG:YOU DON'T NEED XRAY!\n");
			}	
		}
		else {
			if(debugFlag == true) {
				Printf("myDEBUG:YOU NEEEEEEED XRAY!!!!!!\n");
			}	
		}
		
		if(debugFlag == true) {
			Printf("myDEBUG:Doctor wallPocketER nextDEstination %d \n", wallPocketER[mypatientERID]->nextDestination);
		}
		
		ReleaseLock(examRoomLock[mypatientERID]);
		if(debugFlag == true) {
			Printf("myDEBUG: doctor [%d] post the ES\n",id);
		}
		
		ReleaseLock(docLock[id]);
		Printf("Doctor [%d] is going to their office.\n", id);
		
		AcquireLock(patientLeftNumLock);
		if(patientLeftNum == patientNum) {
			Exit(0);
		}
		ReleaseLock(patientLeftNumLock);
	}
}

void cashier() {
	if(debugFlag == true) {
		Printf("myDEBUG: Cashier : I entered!\n");
	}
	
	while(1) {
		AcquireLock(cashierRoomLock); /*The similar scenario as what happened in the waiting room*/
		if(cashierRoomCounter>0) {
			SignalCV(cashierRoomLock, patientWaitingCRCV);
			cashierRoomCounter--;
			cashierState=BUSY;	
			if(debugFlag == true) {
				Printf("myDEBUG:cashier is BUSY now\n");
			}
		}
		
		else{
			cashierState=FREE; /*nobody is waiting in line*/ 
			if(debugFlag == true) {
				Printf("myDEBUG:Cashier is FREE now\n");
			}
		}
		
		AcquireLock(cashierLock);
		ReleaseLock(cashierRoomLock);
		WaitCV(cashierLock,cashierPatientCV); /*wait for patient to come*/
	
		Printf("Cashier receives the examination sheet from Adult Patient [%d]\n",cashierExamSheet->patientID);
		/*print for parent*/
	
	
		bill=moneycalculate(cashierExamSheet);
		Printf("Cashier reads the examination sheet of Adult Patient [%d] and asks him to pay $[%d].\n",cashierExamSheet->patientID, bill);
		/*print for parent*/
	
		SignalCV(cashierLock, cashierPatientCV);  /*Give the bill to the patient. Wait for money given*/
		WaitCV(cashierLock,cashierPatientCV); 
		/*Waiting for patient to pay money*/
		
		Printf("Cashier accepts $[%d] from Adult Patient [%d].\n",bill,cashierExamSheet->patientID);
		/*print for parent*/
		
		/*Give the receipt to the patient*/
		Printf("Cashier gives a receipt of $[%d] to Adult Patient [%d].\n",bill,cashierExamSheet->patientID);
		/*print for parent*/
		
		SignalCV(cashierLock, cashierPatientCV);
		WaitCV(cashierLock,cashierPatientCV);
		ReleaseLock(cashierLock);
		
		AcquireLock(patientLeftNumLock);
		if(patientLeftNum == patientNum) {
			Exit(0);
		}
		ReleaseLock(patientLeftNumLock);
	}
}

void xray () {
	int myNurseId = -1;
	int i = 0;
	struct examSheet *xraySheet = NULL;
	int sympton = -1;
	/*Get index*/
	int id = -1;
	AcquireLock(xrayIndexLock);
	id = xrayIndex;
	xrayIndex++;
	ReleaseLock(xrayIndexLock);
	
	if(debugFlag == true) {
		Printf("myDEBUG: xray [%d]: I entered!\n", id);
	}
	
	AcquireLock(xrayRoomLock[id]);
	while(1) {
		xrayState[id]=FREE;
		if(debugFlag == true) {
			Printf("myDEBUG:XRAY MAN PREPARE TO WAIT!!!\n");
		}
		WaitCV(xrayRoomLock[id],xrayPatientCV[id]);
		
		if(debugFlag == true) {
			Printf("myDEBUG:XRAY MAN WAKEN UP BY PATIENT\n");
		}	
		xraySheet=xrayExamSheet[id];
		/*
		interacion between patient and XRay techinician
		following sequence of signal and printf changed by Tang
		to synchronize with patient
		*/
		Printf("Xray technician [%d] asks Adult Patient [%d] to get on the table.\n",id,xraySheet->patientID);
		SignalCV(xrayRoomLock[id],xrayPatientCV[id]);
		WaitCV(xrayRoomLock[id],xrayPatientCV[id]);
		Printf("Xray Technician [%d] takes an Xray Image of Adult Patient [%d].\n",id,xraySheet->patientID);

		if((xraySheet->imageNum)>1) {
			for(i=0;i<xraySheet->imageNum-1;i++) {
				SignalCV(xrayRoomLock[id],xrayPatientCV[id]);
				Printf("Xray Technician [%d] asks Adult Patient [%d] to move.\n",id,xraySheet->patientID);
				WaitCV(xrayRoomLock[id],xrayPatientCV[id]);
				Printf("Xray Technician [%d] takes another Xray Image of Adult Patient [%d].\n",id,xraySheet->patientID);		
			}
		}
		
		/*record the result to the examination sheet*/
		
		sympton = Rand(3);
		if(sympton ==0) {
			xraySheet->xrayResult=NOTHING;
		}
		else if(sympton == 1) {
			xraySheet->xrayResult = BREAK;
		}
		else{
			xraySheet->xrayResult = COMPOUND;
		}
		
		if(xraySheet->xrayResult == NOTHING){
			Printf("Xray Technician [%d] records nothing on Adult Patient [%d]'s examination sheet.\n",id,xraySheet->patientID);
		}
		else if(xraySheet->xrayResult == BREAK){
			Printf("Xray Technician [%d] records break on Adult Patient [%d]'s examination sheet.\n",id,xraySheet->patientID);
		}
		else if(xraySheet->xrayResult == COMPOUND){
			Printf("Xray Technician [%d] records compound fracture on Adult Patient [%d]'s examination sheet.\n",id,xraySheet->patientID);
		}
		else {
			Printf("ERROR: The X-ray technician give the wrong result\n");
		}

		/*changed the sequence of printf and Signal*/
		Printf("X-ray Technician [%d] tells Patient [%d] to wait in Xray waiting room.\n",id,xraySheet->patientID);
		SignalCV(xrayRoomLock[id],xrayPatientCV[id]);
		
		/*put the examsheet into the wall pocket and finish his task*/
		wallPocketXR[id] = xrayExamSheet[id];
		Printf("Xray Technician put the examsheet into the wall pocket\n");
		
		if(debugFlag == true) {
			Printf("myDEBUG:Xray put the sheet with name %s%d in WallPocetXR\n", wallPocketXR[id]->name,wallPocketXR[id]->patientID);
		}
		WaitCV(xrayRoomLock[id],xrayPatientCV[id]);
		
		AcquireLock(patientLeftNumLock);
		if(patientLeftNum == patientNum) {
			Exit(0);
		}
		ReleaseLock(patientLeftNumLock);
	}
}

void createLock() {
	int i=0;
	/*1. The Lock with the Location*/
	waitingRoomLock = CreateLock("waitingRoomLock", sizeof("waitingRoomLock"));
	for(i=0;i<MAXEXAMROOMNUM;i++) {
		examRoomLock[i] = CreateLock("examRoomLock",sizeof("examRoomLock"));
	}
	for(i=0;i<MAXXRAYNUM;i++) {
		xrayRoomLock[i] = CreateLock("xrayRoomLock",sizeof("xrayRoomLock"));
	}
	sittingRoomLock = CreateLock("sittingRoomLock", sizeof("sittingRoomLock"));
	cashierRoomLock = CreateLock("cashierRoomLock", sizeof("cashierRoomLock"));
	cabinetLock = CreateLock("cabinetLock", sizeof("cabinetLock"));	
	testLock = CreateLock("testLock", sizeof("testLock"));
	
	/*2. The Lock with service providers*/
	wrnLock = CreateLock("wrnLock", sizeof("wrnLock"));
	for(i=0;i<MAXNURSENUM;i++) {
		nurseLock[i] = CreateLock("nurseLock",sizeof("nurseLock"));
	}
	for(i=0;i<MAXDOCNUM;i++) {
		docLock[i] = CreateLock("docLock",sizeof("docLock"));
	}
	cashierLock = CreateLock("cashierLock", sizeof("cashierLock"));

	/*3. The Lock for check state*/
	examStateLock = CreateLock("examStateLock", sizeof("examStateLock"));
	docStateLock = CreateLock("docStateLock", sizeof("docStateLock"));
	xrayStateLock = CreateLock("xrayStateLock", sizeof("xrayStateLock"));
	
	/*4. Relative index lock*/
	patientIndexLock = CreateLock("patientIndexLock", sizeof("patientIndexLock"));
	nurseIndexLock = CreateLock("nurseIndexLock", sizeof("nurseIndexLock"));
	doctorIndexLock = CreateLock("doctorIndexLock", sizeof("doctorIndexLock"));
	xrayIndexLock = CreateLock("xrayIndexLock", sizeof("xrayIndexLock"));
	
	patientLeftNumLock = CreateLock("patientLeftNumLock", sizeof("patientLeftNumLock"));

}
void createCV() {
	int i=0;
	/*1. Person waiting for Room CV*/
	patientWaitingWRCV=CreateCondition("patientWaitingWRCV", sizeof("patientWaitingWRCV"));
	nurseWaitingWRCV=CreateCondition("nurseWaitingWRCV", sizeof("nurseWaitingWRCV"));
	patientWaitingCRCV=CreateCondition("patientWaitingCRCV", sizeof("patientWaitingCRCV"));
	nurseWaitingcabinetCV=CreateCondition("nurseWaitingcabinetCV", sizeof("nurseWaitingcabinetCV"));

	/*2. Person waiting service providers at some Location*/
	patientWaitingNurseSRCV=CreateCondition("patientWaitingNurseSRCV", sizeof("patientWaitingNurseSRCV"));
	nurseWaitingDocCV=CreateCondition("nurseWaitingDocCV", sizeof("nurseWaitingDocCV"));
	for(i=0; i<MAXEXAMROOMNUM; i++){
		patientWaitingNurseERCV[i]=CreateCondition("patientWaitingNurseERCV",sizeof("patientWaitingNurseERCV"));
	}
	for(i=0; i<MAXEXAMROOMNUM; i++){
		patientWaitingDocCV[i]=CreateCondition("patientWaitingDocCV",sizeof("patientWaitingDocCV"));
	}
	for(i=0; i<MAXXRAYNUM; i++){
		patientWaitingNurseXRCV[i]=CreateCondition("patientWaitingNurseXRCV",sizeof("patientWaitingNurseXRCV"));
	}

	/*3. Person interaction CV */
	wrnPatient_NurseCV=CreateCondition("wrnPatient_NurseCV", sizeof("wrnPatient_NurseCV"));
	for(i=0; i<MAXNURSENUM; i++){
		nursePatientCV[i]=CreateCondition("nursePatientCV",sizeof("nursePatientCV"));
	}
	for(i=0; i<MAXDOCNUM; i++){
		docPatientCV[i]=CreateCondition("docPatientCV",sizeof("docPatientCV"));
	}	
	for(i=0; i<MAXXRAYNUM; i++){
		nurseXrayCV[i]=CreateCondition("nurseXrayCV",sizeof("nurseXrayCV"));
	}
	for(i=0; i<MAXXRAYNUM; i++){
		xrayPatientCV[i]=CreateCondition("xrayPatientCV",sizeof("xrayPatientCV"));
	}
	for(i=0; i<MAXDOCNUM; i++){
		nurseDocCV[i]=CreateCondition("nurseDocCV",sizeof("nurseDocCV"));
	}

	cashierPatientCV=CreateCondition("cashierPatientCV", sizeof("cashierPatientCV"));	
}

/*Initial array*/ 
void initialArray(int array[], int arraySize, int value) {
	int i = 0;
	for (i=0;i<arraySize;i++) {
		array[i] = value;
	}
}

void initial (void) {
	int i = 0;
	initialArray(examRoomLock,MAXEXAMROOMNUM,-1);
	initialArray(xrayRoomLock,MAXXRAYNUM,-1);
	initialArray(nurseLock,MAXNURSENUM,-1);
	initialArray(docLock,MAXDOCNUM,-1);

	initialArray(patientWaitingNurseERCV,MAXEXAMROOMNUM,-1);
	initialArray(patientWaitingDocCV,MAXEXAMROOMNUM,-1);
	initialArray(patientWaitingNurseXRCV,MAXXRAYNUM,-1);
	initialArray(nursePatientCV,MAXNURSENUM,-1);
	initialArray(docPatientCV,MAXDOCNUM,-1);
	initialArray(nurseXrayCV,MAXXRAYNUM,-1);
	initialArray(xrayPatientCV,MAXXRAYNUM,-1);
	initialArray(nurseDocCV,MAXDOCNUM,-1);
	
	initialArray(docIDTOPatient,MAXEXAMROOMNUM,INT_MAX);
	initialArray(examIDTODoctor,MAXDOCNUM,INT_MAX);
	initialArray(nurseIDTOXray,MAXXRAYNUM,INT_MAX);
	initialArray(docIDTONurse,MAXNURSENUM,INT_MAX);
	initialArray(nurseIDTOPatientER,MAXEXAMROOMNUM,INT_MAX);
	initialArray(xrayIDTOPatient,MAXNURSENUM,INT_MAX);
	initialArray(nurseIDTOPatientXR,MAXXRAYNUM,INT_MAX);
	initialArray(nurseIDVerify,MAXDOCNUM,INT_MAX);
	initialArray(verifyPatientID,MAXEXAMROOMNUM,INT_MAX);
	initialArray(nurseSheetIDTOPatient,MAXNURSENUM,INT_MAX);
		
	for (i=0;i<examRoomNum;i++) {
		examState[i] = FREE;
	}
	for (i=examRoomNum;i<MAXEXAMROOMNUM;i++) {
		examState[i] = BUSY;
	}	
	for (i=0; i<docNum; i++) {
		docState[i] = BUSY;
	}
	for (i=docNum; i<MAXDOCNUM; i++) {
		docState[i] = BUSY;
	}	
	for(i=0;i<xrayRoomNum;i++){
		xrayState[i]=BUSY;  
	}	
	for(i=xrayRoomNum;i<MAXXRAYNUM;i++){
		xrayState[i]=BUSY;
	}	

/*Initialized the examSheet*/ 
	for (i=0; i<MAXEXAMROOMNUM;i++) {
		wallPocketER[i] = NULL;
	}
	for (i=0; i<MAXXRAYNUM;i++) {
		xrayExamSheet[i] = NULL;
	}	
	for (i=0; i<MAXXRAYNUM;i++) {
		wallPocketXR[i] = NULL;
	}	
	for (i=0; i<MAXDOCNUM;i++) {
		docExamSheet[i] = NULL;
	}	
	/*Initialize nurseIDList*/
	initialArray(nurseIDList,MAXPATIENTNUM,-1);		
}

void doctorOfficeSimulation (void) {
	int i = 0;
	Printf("Welcome to the doctorOffice\n");
	initial();
	
	Printf("Number of Doctors(2 to 3):=[%d]\n",docNum);
	Printf("Number of Nurse(2 - 5)=[%d]\n",nurseNum);
	Printf("Number of Xray Technicians/Rooms(1 - 2)=[%d]\n",xrayRoomNum);
	Printf("Number of Patients=[%d]\n",patientNum);
	Printf("Number of Parents/Child Patients (30 or more)=[%d]\n",parentNum);
	Printf("Number of Examination Rooms(2-5)=[%d]\n",examRoomNum);	

	createLock();
	createCV();

/*Fork the entity*/
	Fork(waitingRoomNurse);
	
	for(i=0; i < patientNum; i++){
		Fork(patient);
	}
	
	for(i=0; i < nurseNum; i++) {
		Fork(Nurse);
	}
	
	for(i=0; i < docNum; i++) {
		Fork(doctor);
	}
	
	for(i=0; i < xrayRoomNum; i++) {
		Fork(xray);
	}
	
	Fork(cashier);
	
/*End the Fork entity*/

	Exit(0);
	
	
}
void main(void) {
	int whichTest;
	bool userInterface = true;
	
	if(userInterface == true) {
		Printf("Please choose the case to test\n");
		Printf("Case 1: Child Patients are never abandoned by their Parent, nor go anywhere without their Parent\n");
		Printf("Case 2: Waiting Room Nurses only talk to on Patient/Parent at a time\n");
		Printf("Case 3: Cashier only talk to one Patient/Parent at a time\n");
		Printf("Case 4: Patients/Parents never go anywhere without being escorted by a Nurse\n");
		Printf("Case 5: All Patients leave the Doctor's Office.\n");
		Printf("Case 6: Two Doctors never examine the same Patient at the same time\n");
		Printf("Case 7: System Simulation: You need to enter the number of entities and rooms\n");
		Printf("Case 0: Exit the doctor office\n");
		Printf("Please behave yourself not trying to enter any characters,OK?\n");
		Printf("The command is: [1,2,3,4,5,6,7,0]\n");
		
		whichTest = InputInt();

		switch (whichTest) {
		case 1:
			Printf("I am going to test case 1\n\n");
			docNum = 1; nurseNum = 1;xrayRoomNum = 1;patientNum = 1;parentNum = 0;
			Printf("SORRY: we do not have time for Parent/Child\n");
			Printf("Please choose other test\n");
			break;
			
		case 2:
			Printf("I am going to test case 2\n\n");
			docNum = 0; nurseNum = 0;xrayRoomNum = 0;patientNum = 5;parentNum = 0;
			doctorOfficeSimulation();
			break;
			
		case 3:
			Printf("I am going to test case 3\n\n");
			docNum = 2; nurseNum = 2;xrayRoomNum = 1;patientNum = 5;parentNum = 0;
			doctorOfficeSimulation();
			break;		
		
		case 4:
			Printf("I am going to test case 4\n\n");
			docNum = 2; nurseNum = 5;xrayRoomNum = 1;patientNum = 5;parentNum = 0;
			doctorOfficeSimulation();
			break;	
			
		case 5:
			Printf("I am going to test case 5\n\n");
			docNum = 2; nurseNum = 5;xrayRoomNum = 2;patientNum = 5;parentNum = 0;
			doctorOfficeSimulation();
			break;		

		case 6:
			Printf("I am going to test case 6\n\n");
			docNum = 2; nurseNum = 2;xrayRoomNum = 1;patientNum = 5;parentNum = 0;
			doctorOfficeSimulation();
			break;
			
		case 7:
			Printf("I am going to test case g\n\n");
			/*Get the input for prompt*/
			
			Printf("Please enter the number of Doctors(2 to 3)\n");
			docNum = InputInt();
			while ( !(docNum >=2&&docNum <=3)){
				Printf("You must input an Integer(2 to 3)\n");
				Printf("Please reenter the number of Doctors(2 to 3)\n");
				docNum = InputInt();					
			}
			
			Printf("Please enter the number of Nurse(2 to 5)\n");
			nurseNum = InputInt();
			while ( !(nurseNum>=2&&nurseNum<=5)){
				Printf("You must input an Integer(2 to 5)\n");
				Printf("Please reenter the number of Nurses(2 to 5)\n");
				nurseNum = InputInt();			
			}
			
			Printf("Please enter the number of Examination Rooms(2 to 5)\n");
			examRoomNum = InputInt();
			while ( !(examRoomNum>=2&&examRoomNum<=5)){ 
				Printf("You must input an Integer(2 to 5)\n");
				Printf("Please reenter the number of Examination Rooms(2 to 5)\n");
				examRoomNum = InputInt();			
			}
			
			Printf("Please enter the number of Xray Technicians/Rooms(1 to 2)\n");
			xrayRoomNum = InputInt();
			while ( !(xrayRoomNum>=1&&xrayRoomNum<=2)){ 
				Printf("You must input an Integer(1 to 2)\n");
				Printf("Please reenter the number of Examination Rooms(1 to 2)\n");
				xrayRoomNum = InputInt();			
			}
			
			Printf("Please enter the number of Patients(1 to 100)\n");
			patientNum = InputInt();
			while ( !(patientNum>=1&&patientNum<=100)){ 
				Printf("You must input an Integer(1 to 100)\n");
				Printf("Please reenter the number of Patients(1 to 100)\n");
				patientNum = InputInt();			
			}
			doctorOfficeSimulation();
			
			break;
		
		case 0:
			break;

		default:
			Printf("Invalid commands!\n\n");
			break;	
		}
	}
	else {
		doctorOfficeSimulation();
	}
	
	
	
	
/*	int try = -1;
	
	Printf("Begin!!!\n\n");
	Printf("the try is %d!!!\n\n",try);
	
	initial();
	
	
	Printf("Number of Doctors(2 to 3):=[%d]\n",docNum);
	Printf("Number of Nurse(2 - 5)=[%d]\n",nurseNum);
	Printf("Number of Xray Technicians/Rooms(1 - 2)=[%d]\n",xrayRoomNum);
	Printf("Number of Patients=[%d]\n",patientNum);
	Printf("Number of Parents/Child Patients (30 or more)=[%d]\n",parentNum);
	Printf("Number of Examination Rooms(2-5)=[%d]\n",examRoomNum);
	
	createLock();
	createCV();
	
	Printf("The waitingRoomLock is %d\n",waitingRoomLock);
	Printf("The cashierLock is %d\n",cashierLock);
	Printf("The xrayStateLock is %d\n",xrayStateLock);
	
	Printf("The patientWaitingNurseSRCV is %d\n",patientWaitingNurseSRCV );
	Printf("The nurseXrayCV[i] is %d\n",nurseXrayCV[MAXXRAYNUM-1]);
	Printf("The cashierPatientCV is %d\n",cashierPatientCV);
	
	wrnExamSheetEmpty = &(examSheetPipe[0]);
	wrnExamSheetEmpty->patientID = 1021;
	wrnExamSheetEmpty->name = "hahah";
	wrnExamSheetEmpty->age = 23;
	Printf("The patient ID is %d\n",wrnExamSheetEmpty->patientID);
	Printf("Waiting Room nurse accepts the form from Adult Patient/Parent with name [%s] and age [%d]\n", wrnExamSheetEmpty->name, wrnExamSheetEmpty->age);
	Printf("Waiting Room nurse creates an examination sheet for [Adult/Child] patient with name [%s] and age [%d]\n", wrnExamSheetEmpty->name, wrnExamSheetEmpty->age);
	Printf("Waiting Room nurse tells the Adult Patient/Parent [%s] to wait in the waiting room for a nurse\n", wrnExamSheetEmpty->name);
	
	try = Rand(100);
	Printf("The random number is %d\n", try);
	try = Rand(100);
	Printf("The random number is %d\n", try);
	try = Rand(100);
	Printf("The random number is %d\n", try);
	try = Rand(100);
	Printf("The random number is %d\n", try);	
	try = Rand(3);
	Printf("The random number is %d\n", try);
	try = Rand(3);
	Printf("The random number is %d\n", try);
	try = Rand(3);
	Printf("The random number is %d\n", try);
	
	try = InputInt();
	Printf("The input is %d\n",try);
	
	try = InputInt();
	Printf("The input is %d\n",try);

*/

}